/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
 * Copyright (C) 2005-2006 Micronas USA Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License (Version 2) as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 */

#include <linux/init.h>
#include <linux/module.h>

#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/viss_isp.h>

#include <media/lombo_viss.h>

#include <mach/debug.h>
#include "../ccc.h"

enum page_id {
	PAGE0_ID,
	PAGE1_ID,
	PAGE2_ID,
};

typedef struct tag_ahd_reg {
	u8 page_id;
	u8 reg_add;
	u8 reg_value;
	u8 rsvd;
} ahd_reg_t;

static struct cc_power_act power_up_act[] = {
	{CC_RESET,  CC_UP},
	{CC_DELAY, 100},
	{CC_RESET, CC_DOWN},
	{CC_DELAY, 100},
	{CC_RESET,  CC_UP},
	{CC_DELAY, 100},
};

static struct cc_power_act power_down_act[] = {
	{CC_RESET, CC_DOWN},
	{CC_DELAY, 100},
};

#define TP3810_WIDTH		1920
#define TP3810_HEIGHT		1080

static const struct cc_frame_cfg frame_cfgs[] = {
	{
		.width = TP3810_WIDTH,
		.height = TP3810_HEIGHT,

		.framerate = { 1, 30 },	/* 30 fps */
		.mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
		.colorspace = V4L2_COLORSPACE_JPEG,
		.field = V4L2_FIELD_NONE,
	},
};

static int tp3810_reg_read(struct cc_sensor_info *cc_si, u8 page_id,
				u8 reg, u8 *val)
{
	int ret = 0;

	/*
	 *ret = cc_si->write_reg(cc_si, 0xFF, page_id);
	 *if (ret != 0) {
	 *	PRT_ERR("page_id=%d\n", page_id);
	 *	goto out;
	 *}
	 *
	 *ret = cc_si->read_reg(cc_si, reg, val);
	 *if (ret != 0)
	 *	PRT_ERR("page_id=%d,reg=0x%02x\n", page_id, reg);

	 */
out:
	return ret;
}

static int tp3810_reg_write(struct cc_sensor_info *cc_si, u8 page_id,
				u8 reg, u8 val)
{
	int ret = 0;

	/*
	 *ret = cc_si->write_reg(cc_si, 0xFF, page_id);
	 *if (ret != 0) {
	 *	PRT_ERR("page_id=%d\n", page_id);
	 *	goto out;
	 *}
	 *
	 *ret = cc_si->write_reg(cc_si, reg, val);
	 *if (ret != 0)
	 *	PRT_ERR("page_id=%d,reg=0x%02x\n", page_id, reg);

	 */
out:
	return ret;
}

static int sensor_detect(struct cc_sensor_info *cc_si)
{
	u8 tmp[2];
	int ret = 0;
	u16 id;

	PRT_ERR("ID tp3810\n");
	return 0;
}

static int sensor_init(struct cc_sensor_info *cc_si)
{
	struct timespec ts_s;
	struct timespec ts_f;
	int i = 0;
	int ret = 0;

	PRT_INFO("\n");

	ret = sensor_detect(cc_si);
	if (ret != 0)
		return ret;

	ktime_get_ts(&ts_s);
	ktime_get_ts(&ts_f);

	PRT_INFO("write %s tp3810 list finish.\n", cc_si->name);
	PRT_INFO("timeused %d %d\n", (int)(ts_f.tv_sec - ts_s.tv_sec),
		(int)(ts_f.tv_nsec - ts_s.tv_nsec));


	return 0;
}

static int sensor_set_stream(struct cc_sensor_info *cc_si, int on)
{
	int ret = 0;

	return ret;
}

/*
 * ctrl for raw sensor finish
 */


#define DRIVER_NAME "tp3810_dvp"

static int sensor_probe(struct platform_device *pdev)
{
	struct cc_sensor_info *cc_si = NULL;
	int ret = 0;

	PRT_INFO("*********probe begin\n");

	cc_si = devm_kzalloc(&pdev->dev, sizeof(*cc_si), GFP_KERNEL);
	if (cc_si == NULL) {
		PRT_ERR("Can't alloc memory!\n");
		return -ENOMEM;
	}

	cc_si->reg_bits = 8;
	cc_si->val_bits = 8;

	cc_si->name = DRIVER_NAME;

	cc_si->power_up_act = power_up_act;
	cc_si->power_down_act = power_down_act;
	cc_si->npwr_up_acts = ARRAY_SIZE(power_up_act);
	cc_si->npwr_dn_acts = ARRAY_SIZE(power_down_act);

	cc_si->framecfgs = frame_cfgs;
	cc_si->nfrmcfgs = ARRAY_SIZE(frame_cfgs);

	ret = cc_sensor_probe(pdev, cc_si);
	if (ret < 0)
		return ret;

	cc_si->detect = sensor_detect;
	cc_si->sensor_init = sensor_init;
	cc_si->set_stream = sensor_set_stream;
	cc_si->sensor_ioctl = NULL;

	PRT_INFO("probe end\n");
	return 0;
}

static int sensor_remove(struct platform_device *pdev)
{
	struct cc_sensor_info *cc_si = platform_get_drvdata(pdev);

	cc_sensor_remove(pdev);

	devm_kfree(&pdev->dev, cc_si);

	return 0;
}

static const struct of_device_id tp3810_of_match[] = {
	{
		.compatible = DRIVER_NAME,
	},
	{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, tp3810_of_match);

static struct platform_driver tp3810_driver = {
	.driver = {
		.of_match_table	= tp3810_of_match,
		.name		= DRIVER_NAME,
		.owner		= THIS_MODULE,
	},
	.probe = sensor_probe,
	.remove = sensor_remove,
};

module_platform_driver(tp3810_driver);

MODULE_DESCRIPTION("TP3810 chip driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRIVER_NAME);
